home *** CD-ROM | disk | FTP | other *** search
- /*
- * callstate.c
- *
- * Machine dependent code to remember and restore the callstate
- * so that we can "squirrel" away a user's function call and make it
- * later.
- *
- *
- * Last modified: 12/21/87
- * by: bnb
- * reason: make preempt safe by updating sp before
- * copy args gets done, rather than after.
- *
- * Chase 8/1/88 added vax code
- */
-
-
-
- #define _CALLSTATE_C
- #include "presto.h"
-
- #ifdef sun
- private_t long _fctaddr;
- #ifdef mc68020
- //
- // nargs.c -- Jim and Janet Carson, 12/27/88 @ 1:04am CST
- //
- // Implementation of C-callable get-number-arguments function
- // for the motorola 680x0 series microprocessors.
- // I suppose this should be inline...
- //
- // This function is dedicated to the poor students of Comp 320,
- // Spring 1989, who had this as a question on their open-book
- // final exam.
- //
- static int _ipc; /* program counter = address of next instruction */
- static short _instr; /* instruction at ipc */
-
- #define ADDQW1 0x584f
- #define ADDQW2 0x504f
- #define LEA 0x4fef
-
- int nargs()
- {
- asm("movl a6, sp@- "); // 1. Save the frame pointer.
- asm("movl a6@, a6 "); // 2. Trace back one frame -- not to
- // the routine that called nargs(),
- // but to the routine that called the
- // routine that called nargs().
- asm("movl a6@(4), __ipc "); // 3. Get the return address
- asm("movl sp@+, a6 "); // 4. Restore the frame pointer
-
- _instr = *((short *) _ipc); // 5. Get the next instruction after the
- // return address. The next
- // instruction is one of the following:
- if (_instr == ADDQW1) // a. addql #4. There was ONE argument.
- return(1);
- else if (_instr == ADDQW2) // b. addql #8. There were TWO arguments.
- return(2);
- else if ( _instr == LEA) // c. lea sp@(JJ), sp. (where JJ is the
- // short word following the lea instr.)
- // There were JJ/4 arguments.
- return ((int)(*(((short *)_ipc)+1))/4);
- else // d. Something else. There were NO
- return(0); // arguments.
- }
- #endif mc68020
- #endif sun
- #ifdef vax
- //
- // Caller's saved AP points to the number of args for caller.
- // Could be an inline asm.
- //
- int
- nargs()
- {
- asm("movl *8(fp), r0");
- }
- #endif
-
- //
- // Callstate set called with:
- // pointer to function to be called later on
- // number of args (longwords) it should get called with
- // a pointer to the base of those args
- //
- // We store this information away and later shove it on to the call
- // stack of the function we want to call.
- //
-
- extern void bcopy(char*, char*, int);
-
- Callstate::~Callstate()
- {
- if (cs_argvd)
- delete cs_argvd;
- }
-
-
- //
- // Copy the arglist into the callstate.
- // If there are args,
- // and the # args > size of cs space, then
- // delete the existing dynamic cs space
- // make some new ones
- // record size of new cs space
- // copy args into new dynamic space
- // else, have enough room somewhere. Copy args
- // into dynamic space (if we have it), else into
- // static area.
- //
- // For the vax, we need to make sure we have two words at the front
- // of the cs_argvd block for the arg count and "this" argument. See
- // comments in Callstate::call below.
- //
- void
- Callstate::set(PFany f, int argc, int *argv)
- {
- register int *ap;
-
- cs_func = f;
- cs_argc = argc;
- if (argc) {
- if (argc > cs_len) {
- delete cs_argvd;
- #ifdef vax
- cs_argvd = new int [argc+2];
- ap = &cs_argvd[2];
- #else
- cs_argvd = new int [argc];
- ap = cs_argvd;
- #endif
- cs_len = cs_argc;
- } else {
- #ifdef vax
- ap = (cs_argvd) ? &cs_argvd[2] : cs_argvs;
- #else
- ap = (cs_argvd) ? cs_argvd : cs_argvs;
- #endif
- }
- bcopy((char*)argv, (char*)ap, argc * sizeof(int));
- }
- }
-
-
- //
- // Perform the actual call.
- //
- // WARNING (for sequent ns32000 version):
- // if the routine we are calling tries to do an nargs
- // its gonna get the wrong answer (0) since we wont
- // have an constant in the adjspb field after the jsr r0
- // 'cest la vie...
- //
-
- void
- Callstate::call(int *sp = 0, Objany obj = 0)
- {
- int local = 0;
- #ifdef sun
- int func = (int)cs_func;
- #else
- int *func = (int *)cs_func;
- #endif sun
- int stackbytes = cs_argc * sizeof(long);
-
- #ifdef vax
- //
- // We want to use CALLG to avoid copying the args onto the stack.
- // This is weird...we need a contiguous block of longwords containing
- // the arg count followed by the arguments. We have to play some games
- // since the arguments may be in the callstate struct itself or they
- // may be in the allocated block pointed to by cs_argvd. If they are
- // in a cs_argvd block, the block will have two extra words at the top
- // for the arg count and the "this" argument.
- //
-
- register int *ap; // ptr to arg block for callg
-
- if (cs_argvd)
- ap = cs_argvd;
- else
- ap = &cs_argc;
-
- //
- // Hack to properly handle "this" argument with callg. Yuck.
- //
- if (obj) {
- ap[0] = ++cs_argc;
- ap[1] = (int)obj;
- } else {
- ap++;
- *ap = cs_argc; // gag
- }
-
- local = (int)ap;
- thisthread->andstate(~TS_VIRGIN); // XXX WINDOW?
-
- asm("callg *-4(fp), *-8(fp)");
- asm("movl r0, -4(fp)");
- #endif vax
-
- #if (sequent || sun)
- //
- // can just toss the args right onto the stack, and do the
- // call ourselves. Remember to adjust the sp correctly
- // once the call returns
- //
- if (sp == 0) { // figure it out for ourselves
- #ifdef ns32000
- asm("sprd sp, -4(fp)");
- #endif
- #ifdef i386
- asm("movl %esp, -4(%ebp)");
- #endif
- #ifdef mc68020
- asm("movl sp, a6@(-4)");
- #endif mc68020
- sp = (int*)local;
- }
-
- //
- // Copy argv from callstate into stack for callee
- // Can't use bcopy here cuz we would be copying over our actual
- // stack.
- //
- if (cs_argc) {
- register int *s = cs_argvd ? (cs_argvd) : (cs_argvs);
- register int *d = (int*)(sp - cs_argc);
- //
- // update where we the sp is before we start
- // writing into the stack. Save ourselves from async
- // interrupts.
- //
- local = (int)(sp - cs_argc);
- #ifdef ns32000
- asm("lprd sp, -4(fp)"); // sp = local
- #endif
- #ifdef i386
- asm("movl -4(%ebp), %esp"); // sp = local
- #endif
- #ifdef mc68020
- asm("movl a6@(-4), sp"); // sp = local;
- #endif mc68020
- while (d != sp)
- *d++ = *s++;
- }
-
- if (obj) {
- // shove hidden first argument "this"
- local = (int)obj;
- #ifdef ns32000
- asm("movd -4(fp), tos"); // sp-- = local
- #endif
- #ifdef i386
- asm("pushl -4(%ebp)"); // sp-- = local
- #endif
- #ifdef mc68020
- asm("movl a6@(-4), sp@-"); // sp-- = local
- #endif mc68020
- }
-
-
- // remember the byte count so we can undo it when func returns
- if (obj)
- local = -(stackbytes + sizeof(Objany)); // (-4(fp))
- else
- local = -stackbytes;
-
-
- //
- // Safe to preempt now that stack has been set
- //
- thisthread->andstate(~TS_VIRGIN);
-
-
- //
- // Call intended function and return anything left over in r0.
- //
- #ifdef mc68020
- asm("movl a6@(-8), __fctaddr " ); // a0 = func
- asm("jsr __fctaddr@ " ); // call func
- asm("addql #4, sp "); // up sp count
- asm("movl d0, a6@(-4) " ); // local = d0
- #endif mc68020
- #ifdef ns32000
- asm("movd -8(fp), r0"); // r0 = func
- asm("jsr r0"); // call
- asm("adjspb -4(fp)"); // up sp count
- asm("movd r0, -4(fp)"); // local = r0;
- #endif
- #ifdef i386
- asm("call *-8(%ebp)"); // call func
- asm("popl %ecx"); // up sp count
- asm("movl %eax, -4(%ebp)"); // local = return value
- #endif
- #endif sequent
-
- thisthread->terminate((Objany)local);
- //
- // NOT REACHED!
- //
-
- }
-
-
- void
- Callstate::print(ostream& s)
- {
- s << form("(Callstate)this=0x%x, cs_func=0x%x, cs_argc=0x%x, cs_argvs=0x%x, cs_argvd=0x%x",
- this, cs_func, cs_argc, cs_argvs, cs_argvd);
- }
-
-
- ostream& operator<<(ostream& s, Callstate& c)
- {
- c.print(s);
- return s;
- }
-